using System.Runtime.CompilerServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif

namespace BepuUtilities
{
    public struct Vector3Wide
    {
        public Vector<float> X;
        public Vector<float> Y;
        public Vector<float> Z;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public Vector3Wide(ref Vector<float> s)
        {
            X = s;
            Y = s;
            Z = s;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Add(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            result.X = a.X + b.X;
            result.Y = a.Y + b.Y;
            result.Z = a.Z + b.Z;
        }
        /// <summary>
        /// 查找向向量的每个分量添加标量的结果。
        /// </summary>
        /// <param name="v">要添加到的向量。</param>
        /// <param name="s">要添加到向量的每个组件的标量。</param>
        /// <param name="result">其组件等于添加到输入标量的输入向量的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Add(in Vector3Wide v, in Vector<float> s, out Vector3Wide result)
        {
            result.X = v.X + s;
            result.Y = v.Y + s;
            result.Z = v.Z + s;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Subtract(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            result.X = a.X - b.X;
            result.Y = a.Y - b.Y;
            result.Z = a.Z - b.Z;
        }

        /// <summary>
        /// 从向量的每个分量中找出减去标量的结果。
        /// </summary>
        /// <param name="v">要从中减去的向量。</param>
        /// <param name="s">从向量的每个分量减去的标量。</param>
        /// <param name="result">分量等于输入向量减去输入标量的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Subtract(in Vector3Wide v, in Vector<float> s, out Vector3Wide result)
        {
            result.X = v.X - s;
            result.Y = v.Y - s;
            result.Z = v.Z - s;
        }
        /// <summary>
        /// 从标量中找出减去向量分量的结果。
        /// </summary>
        /// <param name="v">要从标量中减去的向量。</param>
        /// <param name="s">要从中减去的标量。</param>
        /// <param name="result">分量等于输入标量减去输入向量的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Subtract(in Vector<float> s, in Vector3Wide v, out Vector3Wide result)
        {
            result.X = s - v.X;
            result.Y = s - v.Y;
            result.Z = s - v.Z;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Dot(in Vector3Wide a, in Vector3Wide b, out Vector<float> result)
        {
            result = a.X * b.X + a.Y * b.Y + a.Z * b.Z;
        }

        /// <summary>
        /// 计算标量值和向量各分量之间的每分量最小值。
        /// </summary>
        /// <param name="s">要与每个矢量分量进行比较的标量。</param>
        /// <param name="v">将比较其组件的向量。</param>
        /// <param name="result">其组件与标量值和输入向量中较小者匹配的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Min(in Vector<float> s, in Vector3Wide v, out Vector3Wide result)
        {
            result.X = Vector.Min(s, v.X);
            result.Y = Vector.Min(s, v.Y);
            result.Z = Vector.Min(s, v.Z);
        }
        /// <summary>
        /// 计算每个组件的最小两个向量。
        /// </summary>
        /// <param name="a">将比较其组件的第一个向量。</param>
        /// <param name="b">将比较其组件的第二个向量。</param>
        /// <param name="result">其组件与两个输入向量中较小的一个匹配的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Min(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            result.X = Vector.Min(a.X, b.X);
            result.Y = Vector.Min(a.Y, b.Y);
            result.Z = Vector.Min(a.Z, b.Z);
        }
        /// <summary>
        /// 计算标量值和向量各分量之间的每分量最大值。
        /// </summary>
        /// <param name="s">要与每个矢量分量进行比较的标量。</param>
        /// <param name="v">将比较其组件的向量。</param>
        /// <param name="result">其组件与标量值和输入向量中较大者匹配的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Max(in Vector<float> s, in Vector3Wide v, out Vector3Wide result)
        {
            result.X = Vector.Max(s, v.X);
            result.Y = Vector.Max(s, v.Y);
            result.Z = Vector.Max(s, v.Z);
        }
        /// <summary>
        /// 计算每个组件的最大值两个向量。
        /// </summary>
        /// <param name="a">将比较其组件的第一个向量。</param>
        /// <param name="b">将比较其组件的第二个向量。</param>
        /// <param name="result">其组件与两个输入向量中较大的一个匹配的向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Max(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            result.X = Vector.Max(a.X, b.X);
            result.Y = Vector.Max(a.Y, b.Y);
            result.Z = Vector.Max(a.Z, b.Z);
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Scale(in Vector3Wide vector, in Vector<float> scalar, out Vector3Wide result)
        {
            result.X = vector.X * scalar;
            result.Y = vector.Y * scalar;
            result.Z = vector.Z * scalar;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Abs(in Vector3Wide vector, out Vector3Wide result)
        {
            result.X = Vector.Abs(vector.X);
            result.Y = Vector.Abs(vector.Y);
            result.Z = Vector.Abs(vector.Z);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Negate(in Vector3Wide v, out Vector3Wide result)
        {
            result.X = -v.X;
            result.Y = -v.Y;
            result.Z = -v.Z;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref Vector3Wide Negate(ref Vector3Wide v)
        {
            v.X = -v.X;
            v.Y = -v.Y;
            v.Z = -v.Z;
            return ref v;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ConditionallyNegate(in Vector<int> shouldNegate, ref Vector3Wide v)
        {
            v.X = Vector.ConditionalSelect(shouldNegate, -v.X, v.X);
            v.Y = Vector.ConditionalSelect(shouldNegate, -v.Y, v.Y);
            v.Z = Vector.ConditionalSelect(shouldNegate, -v.Z, v.Z);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ConditionallyNegate(in Vector<int> shouldNegate, in Vector3Wide v, out Vector3Wide negated)
        {
            negated.X = Vector.ConditionalSelect(shouldNegate, -v.X, v.X);
            negated.Y = Vector.ConditionalSelect(shouldNegate, -v.Y, v.Y);
            negated.Z = Vector.ConditionalSelect(shouldNegate, -v.Z, v.Z);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void CrossWithoutOverlap(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            // 如果结果引用实际上是a或b,则此操作将失败！
            result.X = a.Y * b.Z - a.Z * b.Y;
            result.Y = a.Z * b.X - a.X * b.Z;
            result.Z = a.X * b.Y - a.Y * b.X;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Cross(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            CrossWithoutOverlap(a, b, out var temp);
            result = temp;
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void LengthSquared(in Vector3Wide v, out Vector<float> lengthSquared)
        {
            lengthSquared = v.X * v.X + v.Y * v.Y + v.Z * v.Z;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Length(in Vector3Wide v, out Vector<float> length)
        {
            length = Vector.SquareRoot(v.X * v.X + v.Y * v.Y + v.Z * v.Z);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Distance(in Vector3Wide a, in Vector3Wide b, out Vector<float> distance)
        {
            var x = b.X - a.X;
            var y = b.Y - a.Y;
            var z = b.Z - a.Z;
            distance = Vector.SquareRoot(x * x + y * y + z * z);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void DistanceSquared(in Vector3Wide a, in Vector3Wide b, out Vector<float> distanceSquared)
        {
            var x = b.X - a.X;
            var y = b.Y - a.Y;
            var z = b.Z - a.Z;
            distanceSquared = x * x + y * y + z * z;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Normalize(in Vector3Wide v, out Vector3Wide result)
        {
            Length(v, out var length);
            var scale = Vector<float>.One / length;
            Scale(v, scale, out result);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ConditionalSelect(in Vector<int> condition, in Vector3Wide left, in Vector3Wide right, out Vector3Wide result)
        {
            result.X = Vector.ConditionalSelect(condition, left.X, right.X);
            result.Y = Vector.ConditionalSelect(condition, left.Y, right.Y);
            result.Z = Vector.ConditionalSelect(condition, left.Z, right.Z);
        }

        /// <summary>
        /// 将一个向量的分量与另一个向量相乘。
        /// </summary>
        /// <param name="a">要相乘的第一个向量。</param>
        /// <param name="b">要相乘的第二个向量。</param>
        /// <param name="result">乘法结果。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Multiply(in Vector3Wide a, in Vector3Wide b, out Vector3Wide result)
        {
            result.X = a.X * b.X;
            result.Y = a.Y * b.Y;
            result.Z = a.Z * b.Z;
        }

        /// <summary>
        /// 从宽阔的表示中拉出一条车道。
        /// </summary>
        /// <param name="wide">车道的来源。</param>
        /// <param name="slotIndex">要读取的宽表示内车道的索引。</param>
        /// <param name="Narrow">用于存储车道的非SIMD类型。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ReadSlot(ref Vector3Wide wide, int slotIndex, out Vector3 narrow)
        {
            ref var offset = ref GatherScatter.GetOffsetInstance(ref wide, slotIndex);
            ReadFirst(offset, out narrow);
        }


        /// <summary>
        /// 从宽阔的表示中拉出一条车道。
        /// </summary>
        /// <param name="source">车道的来源。</param>
        /// <param name="target">存储车道的非SIMD类型。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ReadFirst(in Vector3Wide source, out Vector3 target)
        {
            target.X = source.X[0];
            target.Y = source.Y[0];
            target.Z = source.Z[0];
        }

        /// <summary>
        /// 从向量中聚集值,并将其放入目标向量的第一个索引中。
        /// </summary>
        /// <param name="source">要从中复制值的向量。</param>
        /// <param name="targetSlot">放置值的宽向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void WriteFirst(in Vector3 source, ref Vector3Wide targetSlot)
        {
            //GatherScatter.GetFirst(ref targetSlot.X) = source.X;
            //GatherScatter.GetFirst(ref targetSlot.Y) = source.Y;
            //GatherScatter.GetFirst(ref targetSlot.Z) = source.Z;
            GatherScatter.SetFirst(ref targetSlot.X, source.X);
            GatherScatter.SetFirst(ref targetSlot.Y, source.Y);
            GatherScatter.SetFirst(ref targetSlot.Z, source.Z);
        }

        /// <summary>
        /// 将值写入目标包的槽中。
        /// </summary>
        /// <param name="source">要写入的值的源。</param>
        /// <param name="slotIndex">要写入的槽的索引。</param>
        /// <param name="target">要将值写入的捆绑包。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void WriteSlot(in Vector3 source, int slotIndex, ref Vector3Wide target)
        {
            WriteFirst(source, ref GatherScatter.GetOffsetInstance(ref target, slotIndex)); 
        }

        /// <summary>
        /// 将每个标量值扩展到束的每个插槽。
        /// </summary>
        /// <param name="source">要写入每个捆绑槽的源值。</param>
        /// <param name="Broadcast">每个插槽中包含源组件的捆绑包。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Broadcast(in Vector3 source, out Vector3Wide broadcasted)
        {
            broadcasted.X = new Vector<float>(source.X);
            broadcasted.Y = new Vector<float>(source.Y);
            broadcasted.Z = new Vector<float>(source.Z);
        }

        /// <summary>
        /// 从源向量获取一个时隙,并将其广播到目标向量的所有时隙。
        /// </summary>
        /// <param name="source">从中拉取值的向量。</param>
        /// <param name="slotIndex">要从中拉取值的源向量中的槽。</param>
        /// <param name="Broadcast">要用所选数据填充的目标向量。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Rebroadcast(in Vector3Wide source, int slotIndex, out Vector3Wide broadcasted)
        {
            broadcasted.X = new Vector<float>(source.X[slotIndex]);
            broadcasted.Y = new Vector<float>(source.Y[slotIndex]);
            broadcasted.Z = new Vector<float>(source.Z[slotIndex]);
        }

        /// <summary>
        /// 从源向量中取出一个槽,并将其放入目标的槽中。
        /// </summary>
        /// <param name="source">从中拉取值的向量。</param>
        /// 要从中拉取值的源向量中的<param name="sourceSlotIndex">槽。</param>
        /// <param name="target">将用所选数据填充其槽的目标向量。</param>
        /// <param name="targetSlotIndex">要写入值的目标向量中的插槽。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void CopySlot(ref Vector3Wide source, int sourceSlotIndex, ref Vector3Wide target, int targetSlotIndex)
        {
            ref var sourceSlot = ref GatherScatter.GetOffsetInstance(ref source, sourceSlotIndex);
            ref var targetSlot = ref GatherScatter.GetOffsetInstance(ref target, targetSlotIndex);
            GatherScatter.GetFirst(ref targetSlot.X) = sourceSlot.X[0];
            GatherScatter.GetFirst(ref targetSlot.Y) = sourceSlot.Y[0];
            GatherScatter.GetFirst(ref targetSlot.Z) = sourceSlot.Z[0];
        }

        public override string ToString()
        {
            return $"<{X}, {Y}, {Z}>";
        }

    }
}
